#ifndef QDC_V792_h
#define QDC_V792_h

#include <sys/types.h>
#include <stdio.h>

#include <iostream>
#include <string>
#include <sstream>
#include "vme_sis.h"
#include "VmeModule.h"
#include "IOError.h"
#include "EventStruct.h"
#include "stringutil.h"

using namespace std;

/*----------------------------------------------------------------------------
Integration of the QDC_V792 by CAEN to Dackel 20070404, Alex Kaplan
----------------------------------------------------------------------------*/

class QDC_V792 : public VmeModule
{
 public:
		
		const static u_int16_t OUTPUT_BUFFER             =0x0000;
		const static u_int16_t OUTPUT_BUFFER_LENGTH      =0x07cf;		
		const static u_int16_t FIRMAWARE_REVISION         =0x1000;
		const static u_int16_t GEO_ADDRESS_REGISTER       =0x1002;
		const static u_int16_t MCST_CBLT_ADDRESS_REGISTER =0x1004;
		const static u_int16_t BITSET_1                   =0x1006;
		const static u_int16_t BITCLEAR_1                 =0x1008;
		const static u_int16_t INTERRUPT_LEVEL            =0x100a;
		const static u_int16_t INTERRUPT_VECTOR           =0x100c;
		const static u_int16_t STATUS_REGISTER_1          =0x100e;
		const static u_int16_t CONTROL_REGISTER_1         =0x1010;
		const static u_int16_t ADER_HIGH                  =0x1012;
		const static u_int16_t ADER_LOW                   =0x1014;
		const static u_int16_t SINGLE_SHOT_RESET          =0x1016;
		const static u_int16_t MCST_CBLT_CTRL             =0x101a;
		const static u_int16_t EVENT_TRIGGER_REGISTER     =0x1020;
		const static u_int16_t STATUS_REGISTER_2          =0x1022;
		const static u_int16_t EVENT_COUNTER_L            =0x1024;
		const static u_int16_t EVENT_COUNTER_H            =0x1026;
		const static u_int16_t INCREMENT_EVENT            =0x1028;
		const static u_int16_t INCREMENT_OFFSET           =0x102a;
		const static u_int16_t LOAD_TEST_REGISTER         =0x102c;
		const static u_int16_t FAST_CLEAR_WINDOW_REGISTER =0x102e;
		const static u_int16_t BITSET_2                   =0x1032;
		const static u_int16_t BITCLEAR_2                 =0x1034;
		const static u_int16_t W_MEMORY_TEST_ADDRESS      =0x1036;
		const static u_int16_t MEMORY_TEST_WORD_HIGH      =0x1038;
		const static u_int16_t MEMORY_TEST_WORD_LOW       =0x103a;
		const static u_int16_t CRATE_SELECT               =0x103c;
		const static u_int16_t TEST_WRITE                 =0x103e;
		const static u_int16_t EVENT_COUNTER_RESET        =0x1040;
		const static u_int16_t IPED                       =0x1060;
		const static u_int16_t R_TEST_ADDRESS             =0x1064;
		const static u_int16_t SW_COMM                    =0x1068;
		const static u_int16_t AAD                        =0x1070;
		const static u_int16_t BAD                        =0x1072;
		const static u_int16_t THRESHOLD_START            =0x1080;

		const static u_int32_t N_CHANNELS                 =32;
		const static u_int16_t PERKEO_CN                  =12;

		//-- bit patterns for output buffer data
		const static u_int32_t MEM_CHANNEL_MASK           =0x00003f00;
		const static u_int16_t MEM_CHANNEL_SHIFT          =8;
		const static u_int32_t VALID_DATUM                =0x00000000;
		const static u_int32_t IS_HEADER                  =0x02000000;
		const static u_int32_t IS_EOB                     =0x04000000;
		const static u_int32_t IS_INVALID_DATUM           =0x06000000;
		const static u_int32_t CHANNEL_MASK               =0x001f0000;
		const static u_int32_t CHANNEL_SHIFT              =16;
		const static u_int32_t VALUE_MASK                 =0x00000fff;
		const static u_int32_t VALUE_SHIFT                =0;
		const static u_int32_t EOB_EVCOUNT_MASK           =0x00ffffff;

    // #########################
    // Bit Set/Clear 1 Register.
    // #########################
    // Bit pattern. If bit is set, the things in the comment happen, if bit is
    // not set (0), they do not happen.

    // Only these bits are allowed to be modified
    const static u_int16_t BITSET_1_ALLOWED_BITS       =0x0098;
    // There was a bus error meaningful in BLT/CBLT modes only
    const static u_int16_t BITSET_1_BERR_FLAG          =0x0008;
    // Select address via  internal ADDR registers
		const static u_int16_t BITSET_1_SELECT_ADDRESS     =0x0010;
		// Software reset status
    const static u_int16_t BITSET_1_SOFTWARE_RESET     =0x0080;

    // #########################
    // Bit Set/Clear 2 Register.
    // #########################
    // Bit pattern. If bit is set, the things in the comment happen, if bit is
    // not set (0), they do not happen.

    // Only these bits are allowed to be modified
    const static u_int16_t BITSET_2_ALLOWED_BITS          =0x78ff;
    // Random memory access test mode
    const static u_int16_t BITSET_2_TEST_MEMORY_MODE      =0x0001;
    // ADC off, no conversion
    const static u_int16_t BITSET_2_OFFLINE               =0x0002;
		// Clear data, counter...
    const static u_int16_t BITSET_2_CLEAR_DATA_BIT        =0x0004;
		// Store overrange data
    const static u_int16_t BITSET_2_OVER_RANGE_ENABLED    =0x0008;
		// Store below threshold data
    const static u_int16_t BITSET_2_LOW_THRESHOLD_ENABLED =0x0010;                                                      
    // Acquisition test mode active
		const static u_int16_t BITSET_2_TEST_ACQ_MODE         =0x0040;
    // Sliding scale enabled
		const static u_int16_t BITSET_2_SLIDE_ENABLE          =0x0080;
		//Treshold is THRESHOLD value * 16, if bit is not set,
		//Treshold is THRESHOLD value * 2
    const static u_int16_t BITSET_2_STEP_THRESHOLD        =0x0080;
    // readout pointer is incremented automaticly
    const static u_int16_t BITSET_2_AUTO_INCREMENT_ENABLE =0x0800;
    // Header written also if there are no accepted cannels
		const static u_int16_t BITSET_2_EMPTY_ENABLE          =0x1000;
    // Subtraction section of sliding scale disabled (only for test!)
    const static u_int16_t BITSET_2_SLIDE_SUBTR_DISABLE   =0x2000;
    // Event counter incremented on all triggers
    const static u_int16_t BITSET_2_ALL_TRIGGERS          =0x4000;
 
    //bits used in the tresholds memory registers
		const static u_int16_t THRESHOLD_MASK                 =0x00ff;
		const static u_int16_t CH_DISABLE_MASK                =0x0100;

		//fast clear stuff
		const static u_int16_t FAST_CLEAR_WINDOW_MASK         =0x03ff;
		const static u_int16_t FAST_CLEAR_WINDOW_MAXWIDTH     =0x03f0;

		// Buffer is empty.
		const static u_int16_t STATUS_REGISTER_2_BUFFER_EMPTY =0x0002; 
		// Buffer is full.
		const static u_int16_t STATUS_REGISTER_2_BUFFER_FULL  =0x0004;


		//constructor
		QDC_V792( int handle, u_int32_t addr );

		u_int32_t GetEventCounter();

		// Read a single event to a DACKEL EventStruct
		// ch0 -> adc00, ch1 -> adc01, ch2 -> adc02
		// ch3 -> adc10, ch4 -> adc11, ch5 -> adc12
		// ch6 -> adc20, ch7 -> adc21, ch8 -> adc22
		// ch9 -> adc30, ch10-> adc31, ch11-> adc32
		// returns the event coutner for the event
		u_int32_t ReadEvent(EventStruct *ev);
		u_int32_t ReadEventFast(EventStruct *ev);
		u_int32_t ReadEvents(EventStruct *ev,u_int32_t num);

    // Set bits of Bit1 register. The function accesses only bits that are
    // allowed to be changed.
		void SetBit1Pattern(u_int16_t pattern);

		// Clears bits of Bit1 register. The function accesses only bits that are
    // allowed to be changed.
    void ClearBit1Pattern(u_int16_t pattern);

    // Set bits of Bit2 register. The function accesses only bits that are
    // allowed to be changed.
		void SetBit2Pattern(u_int16_t pattern);

    // Clears bits of Bit2 register. The function accesses only bits that are
    // allowed to be changed.
		void ClearBit2Pattern(u_int16_t pattern);

		// Performs a software Reset
		void SoftwareReset();
 
		void EnableChannel(u_int16_t ch);
		void DisableChannel(u_int16_t ch);

		void SetThreshold(u_int16_t ch, u_int16_t thr);

		void DefineChannelBehaviour(u_int32_t Pattern);
		void DefineChannelBehaviour(u_int32_t Pattern, u_int16_t Threshold);

		void CountOnlyValidEvents();
		void CountAllEvents();

		u_int16_t GetFastClearWindow();
		void      SetFastClearWindow(u_int16_t width);

		void ClearData();
		void ClearEventCounter();

		bool BufferEmpty();
    bool BufferFull();

		u_int16_t GetStatus1();
		u_int16_t GetStatus2();

};

#endif
